package com.qfedu.fmmall.service.impl;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qfedu.fmmall.common.status.ResStatus;
import com.qfedu.fmmall.common.utils.PageHelper;
import com.qfedu.fmmall.common.vo.ResultVO;
import com.qfedu.fmmall.dao.ProductImgMapper;
import com.qfedu.fmmall.dao.ProductMapper;
import com.qfedu.fmmall.dao.ProductParamsMapper;
import com.qfedu.fmmall.dao.ProductSkuMapper;
import com.qfedu.fmmall.entity.Product;
import com.qfedu.fmmall.entity.ProductImg;
import com.qfedu.fmmall.entity.ProductParams;
import com.qfedu.fmmall.entity.ProductSku;
import com.qfedu.fmmall.service.ProductService;
import com.qfedu.fmmall.vo.Product4ES;
import com.qfedu.fmmall.vo.ProductVO;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author : yanBin
 * @date :2021/12/15 16:49
 */
@Service
public class ProductServiceImpl implements ProductService {
    private static final Logger log = LoggerFactory.getLogger(ProductServiceImpl.class);

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductImgMapper productImgMapper;

    @Autowired
    private ProductSkuMapper productSkuMapper;

    @Autowired
    private ProductParamsMapper productParamsMapper;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public ResultVO listRecommendProducts() {
        try {
            return new ResultVO(ResStatus.OK.ordinal(), "获取推荐算法成功", productMapper.selectRecommendProducts());
        } catch (Exception e) {
            return new ResultVO(ResStatus.NO.ordinal(), "获取推荐算法失败", null);
        }

    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public ResultVO getProductBasicInfo(String productId) {
        Map<String, Object> basicInfo = new HashMap<>();
        try {
            //用Id在redis查询商品信息
            String productInfo = (String) stringRedisTemplate.boundHashOps("products").get(productId);
            if (StringUtils.isNotBlank(productInfo)) {
                Product product = objectMapper.readValue(productInfo, Product.class);
                basicInfo.put("product", product);
            } else {
                //用Id在数据库查询商品信息
                Example example = new Example(Product.class);
                Example.Criteria criteria = example.createCriteria();
                criteria.andEqualTo("productId", productId);
                criteria.andEqualTo("productStatus", 1);
                List<Product> products = productMapper.selectByExample(example);
                if (CollectionUtils.isEmpty(products)) {
                    return new ResultVO(ResStatus.NO.getCode(), "此商品没有上架", null);
                }
                //把查询结果放入redis中
                String productJson = objectMapper.writeValueAsString(products.get(0));
                stringRedisTemplate.boundHashOps("products").put(productId, productJson);
                //设置过期时间为一天
                stringRedisTemplate.boundHashOps("products").expire(1, TimeUnit.DAYS);
                basicInfo.put("product", products.get(0));
            }

            //用Id在redis查询商品图片信息
            String productImgs1 = (String) stringRedisTemplate.boundHashOps("productImgs").get(productId);
            if (StringUtils.isNotBlank(productImgs1)) {
                JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ProductImg.class);
                List<ProductImg> productImg2 = objectMapper.readValue(productImgs1, javaType);
                basicInfo.put("productImgs", productImg2);
            } else {
                //用Id在数据库查询商品图片信息
                Example example1 = new Example(ProductImg.class);
                Example.Criteria criteria1 = example1.createCriteria();
                criteria1.andEqualTo("itemId", productId);
                List<ProductImg> productImgs = productImgMapper.selectByExample(example1);
                //把查询结果放入redis中
                String productImgJson = objectMapper.writeValueAsString(productImgs);
                stringRedisTemplate.boundHashOps("productImgs").put(productId, productImgJson);
                //设置过期时间为一天零一分钟
                stringRedisTemplate.boundHashOps("productImgs").expire(24 * 60 + 1, TimeUnit.MINUTES);
                basicInfo.put("productImgs", productImgs);
            }

            //用Id在redis查询商品库存信息
            String productSkuString = (String) stringRedisTemplate.boundHashOps("productSkus").get(productId);
            if (StringUtils.isNotBlank(productSkuString)) {
                JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, ProductSku.class);
                List<ProductSku> productSkuList = objectMapper.readValue(productSkuString, javaType);
                basicInfo.put("productSkus", productSkuList);
            } else {
                //用Id在数据库查询商品库存信息
                Example example2 = new Example(ProductSku.class);
                Example.Criteria criteria2 = example2.createCriteria();
                criteria2.andEqualTo("productId", productId);
                criteria2.andEqualTo("status", 1);
                List<ProductSku> productSkus = productSkuMapper.selectByExample(example2);
                //把查询结果放入redis中
                String productSkusJson = objectMapper.writeValueAsString(productSkus);
                stringRedisTemplate.boundHashOps("productSkus").put(productId, productSkusJson);
                //设置过期时间为一天零2分钟
                stringRedisTemplate.boundHashOps("productSkus").expire(24 * 60 + 2, TimeUnit.MINUTES);
                basicInfo.put("productSkus", productSkus);
            }
            return new ResultVO(ResStatus.OK.ordinal(), "商品查询成功", basicInfo);

        } catch (Exception e) {
            return new ResultVO(ResStatus.NO.getCode(), e.getLocalizedMessage(), null);
        }

    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public ResultVO getProductParamsById(String productId) {
        try {
            Example example = new Example(ProductParams.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("productId", productId);
            List<ProductParams> productParams = productParamsMapper.selectByExample(example);
            if (CollectionUtils.isEmpty(productParams)) {
                return new ResultVO(ResStatus.NO.ordinal(), "没有商品参数", null);
            }
            return new ResultVO(ResStatus.OK.ordinal(), "查询商品参数成功", productParams.get(0));
        } catch (Exception e) {
            log.error(e.getLocalizedMessage());
            return new ResultVO(ResStatus.NO.ordinal(), "查询商品参数失败", "失败原因: " + e.getLocalizedMessage());
        }

    }

    @Override
    public ResultVO getProductByCategoryId(int categoryId, int page, int size) {
        int start = (page - 1) * size <= 0 ? 0 : (page - 1) * size;
        int limit = size == 0 ? 10 : size;
        List<ProductVO> productVOS = productMapper.selectProductByCategoryId(categoryId, start, limit);
        Example example = new Example(Product.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("categoryId", categoryId);
        int count = productMapper.selectCountByExample(example);
        int pageCount = count % limit == 0 ? count / limit : count / limit + 1;
        PageHelper<ProductVO> productVOPageHelper = new PageHelper<>(count, pageCount, productVOS);
        return new ResultVO(ResStatus.OK.ordinal(), "查询三级分类成功", productVOPageHelper);
    }

    @Override
    public ResultVO listBrands(int categoryId) {
        List<String> brands = productMapper.selectBrandByCategoryId(categoryId);
        return new ResultVO(ResStatus.OK.ordinal(), "查询品牌成功", brands);
    }

    @Override
    public ResultVO searchProduct(String keyword, int page, int size) {

        ResultVO resultVO = null;
        int start = (page - 1) * size <= 0 ? 0 : (page - 1) * size;
        int limit = size == 0 ? 10 : size;
        //首先在es查询
        try {
            SearchRequest searchRequest = new SearchRequest("fmmallproducrsindex");
            //用SearchSourceBuilder来封装搜索条件。
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //查询条件
            //searchSourceBuilder.query(QueryBuilders.matchAllQuery()); //表示查询所有数据
            //searchSourceBuilder.query(QueryBuilders.matchQuery("productName","饼干")); //一个搜索条件对应一个搜索变量
            //一个搜索条件对应多个搜索变量
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery(keyword, "productName", "productSkuName"));

            //分页规则
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(size);

            //高亮显示
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            //设置商品名字高亮
            HighlightBuilder.Field field = new HighlightBuilder.Field("productName");
            HighlightBuilder.Field field1 = new HighlightBuilder.Field("productSkuName");

            highlightBuilder.field(field);
            highlightBuilder.field(field1);
            //设置高亮颜色为红色
            highlightBuilder.preTags("<label style ='color:red'>");
            highlightBuilder.postTags("</label>");

            //把高亮条件放入封装类
            searchSourceBuilder.highlighter(highlightBuilder);

            //把搜索条件放入到封装类searchRequest
            searchRequest.source(searchSourceBuilder);
            //查询es并返回数据
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //获取查询到的数据
            SearchHits hits = searchResponse.getHits();

            //获取查询到的数据总条数
            int count = (int)(hits.getTotalHits().value);
            //根据总条数算出总页数
            int pageCount =count % limit == 0 ? count / limit : count / limit + 1;


            //把查询的信息封装成product对象
            List<Product4ES> productsList = new ArrayList<>();
            Iterator<SearchHit> iterator = hits.iterator();
            while (iterator.hasNext()) {
                //封装查询数据
                SearchHit searchHit = iterator.next();
                String sourceAsString = searchHit.getSourceAsString();
                Product4ES product4ES = objectMapper.readValue(sourceAsString, Product4ES.class);
                //高亮显示
                Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                HighlightField highlightField = highlightFields.get("productName");
                if (highlightField != null) {
                    Text[] fragments = highlightField.fragments();
                    String highlightProductName = Arrays.toString(fragments);
                    product4ES.setProductName(highlightProductName);
                }
                HighlightField highlightField1 = highlightFields.get("productDesc");
                if (highlightField1 != null){
                    Text[] fragments = highlightField1.fragments();
                    String highlightProductSkuName = Arrays.toString(fragments);
                    product4ES.setProductSkuName(highlightProductSkuName);
                }
                productsList.add(product4ES);
            }

            PageHelper<Product4ES> productVOPageHelper = new PageHelper<>(count, pageCount, productsList);
            resultVO = new ResultVO(ResStatus.OK.ordinal(), "搜索成功",productVOPageHelper);
        } catch (Exception e) {

           resultVO = new ResultVO(ResStatus.NO.ordinal(), "搜索失败",null);
        }
        return resultVO;
//        keyword = "%" + keyword + "%";
//        List<ProductVO> productVOS = productMapper.selectProductByKeyword(keyword, start, limit);
//
//        Example example = new Example(Product.class);
//        Example.Criteria criteria = example.createCriteria();
//        criteria.andLike("productName", keyword);
//        int count = productMapper.selectCountByExample(example);
//        int pageCount = count % limit == 0 ? count / limit : count / limit + 1;
//        PageHelper<ProductVO> productVOPageHelper = new PageHelper<>(count, pageCount, productVOS);
//        return new ResultVO(ResStatus.OK.ordinal(), "查询三级分类成功", productVOPageHelper);
    }

    @Override
    public ResultVO listBrandsByKeyword(String keyword) {
        List<String> brand = productMapper.selectBrandByKeyword(keyword);
        return new ResultVO(ResStatus.OK.ordinal(), "查询品牌成功", brand);

    }
}
